package com.oak.interviewdemo.utils;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.oak.interviewdemo.exception.GlobalException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.Date;

/**
 * JwtUtil
 * 总的来说，工具类中有三个方法
 * 获取JwtToken，获取JwtToken中封装的信息，判断JwtToken是否存在
 * 1. encode()，参数是=签发人，存在时间，一些其他的信息=。返回值是JwtToken对应的字符串
 * 2. decode()，参数是=JwtToken=。返回值是荷载部分的键值对
 * 3. isVerify()，参数是=JwtToken=。返回值是这个JwtToken是否存在
 *
 * @Author: guoxy
 * @Date: 2020/5/14 22:35
 * @Description:
 * @Version: 1.0
 */
@Slf4j
@Component
public class JwtUtil {

    /**
     * 过期时间30分钟
     */
    private static final long EXPIRE_TIME = 30 * 60 * 1000L;

    private static final String JWT_NAME = "username";

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(JWT_NAME, username)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {
            log.error("校验token异常: ", e);
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(JWT_NAME).asString();
        } catch (JWTDecodeException e) {
            log.error("获取用户名异常: ", e);
            return null;
        }
    }

    /**
     * 生成签名,5min后过期
     *
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            return JWT.create()
                    .withClaim(JWT_NAME, username)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (UnsupportedEncodingException e) {
            log.error("生成token异常: ", e);
            return null;
        }
    }


    /**
     * 根据request中的token获取用户账号
     *
     * @param request
     * @return
     * @throws GlobalException
     */
    public static String getUserNameByToken(HttpServletRequest request) throws GlobalException {
        String accessToken = request.getHeader("X-Access-Token");
        String username = getUsername(accessToken);
        if (StrUtil.isBlank(username)) {
            throw new GlobalException("未获取到用户");
        }
        return username;
    }

    public static void main(String[] args) throws InterruptedException {
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1ODk4NzgxNzAsInVzZXJuYW1lIjoiYWRtaW4ifQ.z7nUBbJRzi2hqW7sLB9tUCL4OuuvHBqOvCq3_wfrROs
        String username = "admin";
        String secret = "123456";
        String token = JwtUtil.sign(username, secret);
        System.out.println(token);
        String usernames = getUsername(token);
        boolean bool = verify(token, username, secret);
        System.out.println(bool);
//        Thread.sleep(6 * 1000);

        boolean bool2 = verify(token, username, secret);
        System.out.println("五秒后过期：" + bool2);

    }
}